package org.ala.tiktools.rpc.kcp.protocol.receiver.queue;

import java.util.List;

import org.ala.tiktools.rpc.kcp.protocol.IKcpReceiverQueue;
import org.ala.tiktools.rpc.kcp.protocol.segment.KcpSegment;
import org.ala.tiktools.tools.queue.DoubleLinkedQueue;
import org.ala.tiktools.tools.queue.IQueueIterator;

import io.netty.buffer.ByteBuf;

/**
 *	接收队列
 *
 *	@author ala
 *	@date 2025年4月29日
 */
public class KcpReceiveLinkedQueue extends DoubleLinkedQueue<KcpSegment> implements IKcpReceiverQueue {

	
	@Override
	public boolean isWarningLine(int rcvWnd) {
		return size() >= rcvWnd;
	}
	

	@Override
	public void clear() {
		IQueueIterator<KcpSegment> iterator = firstIterator();
		while (iterator.hasNext()) {
			KcpSegment seg = iterator.removeAndNext();
			seg.recycle(true);
		}
	}


	/**
     *  rcvQue 中一个完整消息的字节数
     *  <p>	其实可以在add的时候做成O(1)
     *  
     *  @return -1:queue为空 | -2:queue中还么有收到一个完整消息 | >0 一个完整消息的字节数
	 */
	@Override
	public int peekSize() {
		if (isEmpty()) { return -1; }
		
		KcpSegment seg = first();
		//	frg是从0开始倒排的，frg+1就是被切分的一个消息的数量。
		//	如果 > size 说明队列中肯定没有一个完整消息
		if (seg.getFrg()+1 > size()) { return -2; }
		
		int len = 0;
		IQueueIterator<KcpSegment> iterator = firstIterator();
		while (iterator.hasNext()) {
			seg = iterator.next();
			len += seg.getData().readableBytes();
			if (seg.getFrg() == 0) {break;}
		}
		return len;
	}

	
	/**
	 * 	读一个完整消息到buf中
     *  rcvQue -> ByteBuf，直到frg == 0为止
     *  @return  读取的字节数
     */
	@Override
	public int writeToByteBufAndRemove(ByteBuf buf) {
		IQueueIterator<KcpSegment> iterator = firstIterator();
		int len = 0;
		while (iterator.hasNext()) {
			KcpSegment seg = iterator.removeAndNext();
			len += seg.getData().readableBytes();
			buf.writeBytes(seg.getData());
			
			int frg = seg.getFrg();
			seg.recycle(true);
			if (frg == 0) { break; }
		}
		return len;
	}

	
	/**
	 * 	读一个完整消息到buf中
     *  rcvQue -> ByteBuf，直到frg == 0为止
     *  @return  读取的字节数
     */
	@Override
	public int writeToByteBufsAndRemove(List<ByteBuf> bufs) {
		IQueueIterator<KcpSegment> iterator = firstIterator();
		int len = 0;
		while (iterator.hasNext()) {
			KcpSegment seg = iterator.current();
			len += seg.getData().readableBytes();
			bufs.add(seg.getData());
			
			iterator.removeAndNext();
			int frg = seg.getFrg();
			seg.recycle(false);
			if (frg == 0) { break; }
		}
		return len;
	}

	
	/**
     *  将受到的数据按sn号升序放入sndBuf列表
     *  <p>	从末尾开始找，如果队中某个节点的sn号 < seg.sn，则seg就插在该节点后面
     *  <p> sn号大概率收到的是排在末尾的
     *  <p>	其实可以在add的时候判断：断掉的地方存进hash，用hash做到O(1)
     */
	@Override
	public void parseData(KcpSegment seg) {
		IQueueIterator<KcpSegment> iterator = lastIterator();
		
		//	如果第一个位置都 > seg.sn，那seg保存在首位
		if (isEmpty() || first().getSn() > seg.getSn()) {
			addFirst(seg);
			return;
		}
		
		while (iterator.hasPrev()) {
			KcpSegment crt = iterator.current();
			//	如果找到了位置，直接插入
			if (crt.getSn() < seg.getSn()) {
				iterator.insert(crt);
				break;
			}
			//	如果重复收到了，直接丢弃
			if (crt.getSn() == seg.getSn()) {
				break;
			}
			iterator.prev();
		}
	}

}
